
第 5 回で、メモアプリは API からの取得と端末への保存ができるようになりました。最終回の第 6 回は、
- メモを書く画面を作り、一覧から移動して結果を受け取る(画面遷移)
- ウィジェットテストで、操作を自動で確かめる
- App Store・Google Play に公開するためのビルドと準備
を解説し、全 6 回をまとめます。

画面遷移: Navigator で移動して、結果を受け取る
Flutter の画面遷移は、画面を積み重ねるスタックです。Navigator.push で新しい画面を上に積み、Navigator.pop で取り除いて前の画面に戻ります。pop のときに値を渡すと、前の画面で受け取れます。
Future<void> _openEditor(BuildContext context) async {
final text = await Navigator.push<String>(
context,
MaterialPageRoute(builder: (_) => const MemoEditPage()),
);
if (text != null) store.add(text); // 戻るボタンで閉じたときは null
}メモを書く画面
class MemoEditPage extends StatefulWidget {
const MemoEditPage({super.key, this.initialText = ''});
final String initialText;
@override
State<MemoEditPage> createState() => _MemoEditPageState();
}
class _MemoEditPageState extends State<MemoEditPage> {
late final _controller = TextEditingController(text: widget.initialText);
@override
void dispose() {
_controller.dispose(); // 使い終わったら片付ける
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('メモを書く')),
body: Padding(
padding: const EdgeInsets.all(16),
child: TextField(
controller: _controller,
autofocus: true,
maxLength: 100,
decoration: const InputDecoration(
labelText: 'メモ',
border: OutlineInputBorder(),
),
),
),
floatingActionButton: FloatingActionButton.extended(
onPressed: () => Navigator.pop(context, _controller.text),
icon: const Icon(Icons.check),
label: const Text('保存'),
),
);
}
}- 入力中の文字は `TextEditingController` で読み書きします。画面を閉じるときは
disposeで片付けます late finalは「最初に使うときに作る」変数です。widget.initialTextを使って作れます- 画面がたくさんあるアプリでは、URL のように画面を指定できる go_router などのパッケージもよく使われます

ウィジェットテスト: 操作を自動で確かめる
Flutter には、画面を実際に組み立てて、タップや入力をシミュレーションするウィジェットテストの仕組みが標準で入っています。この講座のメモアプリも、次のテストで動作を確かめています。
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:http/http.dart' as http;
import 'package:http/testing.dart';
import 'package:memo_app/main.dart';
import 'package:memo_app/memo_repository.dart';
import 'package:memo_app/memo_store.dart';
import 'package:memo_app/quote_api.dart';
void main() {
testWidgets('メモを追加して完了にできる', (tester) async {
final store = MemoStore(InMemoryMemoRepository());
final api = SuggestionApi(
client: MockClient(
(_) async => http.Response.bytes(utf8.encode('{"title":"テスト"}'), 200),
),
);
await tester.pumpWidget(MemoApp(store: store, api: api));
expect(find.text('メモはまだありません'), findsOneWidget);
// +ボタン → 入力 → 保存
await tester.tap(find.byIcon(Icons.add));
await tester.pumpAndSettle();
await tester.enterText(find.byType(TextField), '牛乳を買う');
await tester.tap(find.text('保存'));
await tester.pumpAndSettle();
expect(find.text('牛乳を買う'), findsOneWidget);
expect(find.text('メモ(残り 1 件)'), findsOneWidget);
// チェックを入れると残りが 0 件に
await tester.tap(find.byType(Checkbox));
await tester.pump();
expect(find.text('メモ(残り 0 件)'), findsOneWidget);
// API から候補を取得
await tester.tap(find.byIcon(Icons.cloud_download_outlined));
await tester.pumpAndSettle();
expect(find.text('テスト'), findsOneWidget);
});
}flutter test00:00 +1: All tests passed!- 保存先は `InMemoryMemoRepository`、通信は `MockClient` に差し替えています。第 5 回で「外から渡せる」作りにしたのは、このためです
pump()は 1 回だけ描き直し、pumpAndSettle()は画面遷移などのアニメーションが終わるまで待ちます- コードを変えるたびに
flutter testを実行すれば、「直したら別の場所が壊れた」をすぐに見つけられます
リリースのビルド
バージョンを決める
アプリのバージョンは pubspec.yaml の version で決めます。+ の前が利用者に見えるバージョン、後ろがストア用の通し番号(ビルド番号)です。
version: 1.0.0+1Android: App Bundle を作る
Google Play には App Bundle(.aab) の形式で提出します。リリース版には、アップロード用の鍵で署名する必要があります。鍵は次のコマンドで作り、パスワードとともになくさないように保管します(Git には入れません)。
keytool -genkey -v -keystore ~/upload-keystore.jks -keyalg RSA \
-keysize 2048 -validity 10000 -alias upload鍵の情報を android/key.properties に書き、android/app/build.gradle.kts から読み込む設定をしたら、ビルドします(設定の詳しい手順は公式ドキュメントの「Build and release an Android app」にあります)。
flutter build appbundle
# → build/app/outputs/bundle/release/ に .aab ファイルができるiOS: IPA を作る
App Store に公開するには、Apple Developer Program への登録が必要です。Xcode でチームと署名を設定してから、ビルドします。
flutter build ipa
# → build/ios/archive/ と build/ios/ipa/ に出力できたファイルは、Apple の Transporter アプリや Xcode からアップロードします。
iOS の対応バージョンに注意
Flutter は iOS 13 以降に対応していますが、使う Xcode のバージョンによっては、それより新しい対応バージョン(デプロイメントターゲット)の指定が必要になることがあります。当社の環境(Xcode 27.2)では、ios/Podfile と Xcode のプロジェクトの設定を 15.0 にしてビルドが通りました。
platform :ios, '15.0'
post_install do |installer|
installer.pods_project.targets.each do |target|
flutter_additional_ios_build_settings(target)
target.build_configurations.each do |config|
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '15.0'
end
end
endストアに公開するまでの準備
ビルドのほかにも、公開までにはいくつかの準備があります。

準備 | 内容 |
|---|---|
開発者の登録 | Apple Developer Program(年額)・Google Play Console(初回の登録料)。会社として登録する場合は、組織の確認に日数がかかることがあります |
アプリのアイコン | iOS・Android の各サイズ。 |
ストアの掲載情報 | アプリ名・説明文・スクリーンショット・カテゴリー |
プライバシー | プライバシーポリシーの URL、集めるデータの申告(App Store のプライバシー情報、Google Play のデータセーフティ) |
審査 | 内容によっては修正を求められます。ログインが必要なアプリは、審査用のアカウントを用意します |
全 6 回のまとめ
- Flutter とは・開発環境: 1 つの Dart のコードで iOS・Android・Web などを作れる。VS Code の拡張機能と
flutter doctorで準備 - Dart の基本:
finalが基本、null 安全、名前付き引数、async/await、レコードとパターン - ウィジェット: すべてがウィジェット。Scaffold で骨組み、Column・Row でレイアウト、ListView で一覧
- 状態管理: 画面の中は
setState、アプリ全体はChangeNotifierとListenableBuilder - 通信と保存: http で API、
SharedPreferencesAsyncで端末に保存。保存先や通信は差し替えられる作りに - 画面遷移・テスト・リリース: Navigator、ウィジェットテスト、App Bundle と IPA、ストアの準備
ここまでで、一覧・入力・保存・通信・テストという、多くのアプリに共通する基本がそろいました。次のステップとしては、ログイン(認証)、サーバー側のデータベースとの連携、プッシュ通知、画面の多いアプリでのルーティング(go_router など)や状態管理のパッケージに進むのがおすすめです。
当社では、Flutter をはじめとしたスマートフォンアプリの開発や、業務システム・Web サービスと連携するアプリの開発を承っています。「講座を読んで試作したが、本番のアプリはプロに任せたい」「既存のシステムとつなぐアプリを作りたい」といったご相談もお気軽にどうぞ。
企画・設計から、開発・ストアへの公開・公開後の保守まで対応します。フォームは 24 時間受付です
Flutter 入門講座(全 6 回)
- Flutter とは?できることと開発環境の作り方
- Dart の基本文法
- ウィジェットで画面を作る
- 状態管理の第一歩
- API からデータを取得し、端末に保存する
- 画面遷移・テスト・リリースまで(この記事)
※ Flutter・Dart・Android・Google Play は Google LLC の商標です。iOS・Xcode・App Store・Apple Developer Program は Apple Inc. の商標です。
参考
- Flutter 公式ドキュメント「Navigate to a new screen and back」
- Flutter 公式ドキュメント「An introduction to widget testing」
- Flutter 公式ドキュメント「Build and release an Android app」「Build and release an iOS app」





